const express = require('express')
const router = express.Router()

// 自定义库
const db = require('../config/database.js')
const code = require('../config/code.js')
const redis = require('../config/redis.js')
const mailer = require('../config/mailer.js')
const token = require('../config/token.js')
const captcha = require('../config/captcha.js')
const { getAuthCode, encryptPassword, makeId } = require('../utils/index.js')
const User = require('../model/user.js')


/**
 * @openapi
 * /api/oper/authcode:
 *   post:
 *     summary: 获取验证码
 *     parameters:
 *      - name: email
 *        in: body
 *        required: true
 *        schema:
 *          type: string
 *     responses:
 *       2000:
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: string
 *                   example: 获取成功，请前往邮箱查看
 *       other:
 *         description: 获取失败
 */
router.get('/authcode', (req, res, next) => {
  (async () => {
    const { email, type } = req.query
    const errTips = {
      email: '请输入邮箱',
      type: '请传入验证码类型'
    }
    for (const key in errTips) {
      if (!req.query[key]) {
        res.json({code: code.paraErr, msg: errTips[key]})
        return
      }
    }
    if (!['register', 'reset'].includes(type)) {
      res.json({code: code.paraErr, msg: '请传入正确的验证码类型'})
      return
    }
    // 查看缓存中是否已经缓存该数据
    const key = email + type
    const emailCache = await redis.hGetAll(key)
    if (Object.keys(emailCache).length !== 0) {
      const timeDiff = 60 - parseInt((Date.now() - emailCache.storetime) / 1000)
      if (timeDiff > 0) {
        res.json({code: code.err, msg: `请在${timeDiff}s之后重新获取`, data: {time: timeDiff}})
        return
      }
    }
    const authcode = getAuthCode()
    console.log(authcode)
    // 发送注册邮件，这里采用异步，不管邮件是否发送完成，都直接返回信息
    if (type === 'register') {
      mailer.sendMail(mailer.registerConfig(email, authcode))
    } else if (type === 'reset') {
      mailer.sendMail(mailer.resetConfig(email, authcode))
    }
    // 缓存注册信息
    await redis.multi()
      .hSet(key, 'authcode', authcode)
      .hSet(key, 'storetime', Date.now())
      .expire(key, 600)
      .exec()
    res.json({code: code.ok, msg: '获取成功，请前往邮箱查看'})
  })()
})

router.get('/captcha', (req, res, next) => {
  (async () => {
    const svg = captcha.make()
    const svgId = makeId()
    await redis.set(svgId, svg.text, {
      EX: 600
    })
    res.json({
      code: code.ok,
      msg: '获取成功',
      data: {
        svgId: svgId,
        svg: svg.data
      }
    })
  })()
})

router.post('/register', (req, res, next) => {
  (async () => {
    try {
      const { email, authcode, password, nickname, realname, phone, identity } = req.body
      const errTips = {
        email: '请输入邮箱',
        authcode: '请输入验证码',
        password: '请输入密码',
        nickname: '请输入昵称',
        realname: '请输入真实姓名',
        phone: '请输入手机号码',
        identity: '请选择身份'
      }
      for (const key in errTips) {
        if (!req.body[key]) {
          res.json({code: code.paraErr, msg: errTips[key]})
          return
        }
      }
      // 查看缓存中是否已经缓存该数据
      const key = email + 'register'
      const emailCache = await redis.hGetAll(key)
      if (Object.keys(emailCache).length === 0) {
        res.json({code: code.paraErr, msg: '请获取邮箱验证码'})
        return
      } else {
        if (emailCache.authcode !== authcode) {
          res.json({code: code.paraErr, msg: '邮箱验证码不正确'})
          return
        }
      }
      // 删除验证码
      await redis.multi()
        .hDel(key, 'authcode')
        .hDel(key, 'storetime')
        .exec()
      const [errFind, ids] = await db.query(User.findIdByEmail, [email])
      if (errFind) {
        res.json({code: code.dbErr, msg: '注册失败'})
        return
      }
      if (ids.length !== 0) {
        res.json({code: code.paraErr, msg: '该用户已存在'})
        return
      }
      const [errAdd, info] = await db.query(User.addUser, 
        [email, encryptPassword(password), nickname, realname, phone, identity])
      if (errAdd) {
        res.json({code: code.dbErr, msg: '注册失败'})
        return
      }
      if (info.affectedRows === 0) {
        res.json({code: code.dbErr, msg: '注册失败'})
        return
      }
      res.json({code: code.ok, msg: '注册成功'})
    } catch(e) {
      res.json({code: code.insErr, msg: "注册失败"})
    }
  })()
})

router.post('/login', (req, res, next) => {
  (async () => {
    const { email, password, captchaId, captchaText } = req.body
    const errTips = {
      email: '请输入邮箱',
      password: '请输入密码',
      captchaId: '缺少参数',
      captchaText: '请输入图形验证码'
    }
    for (const key in errTips) {
      if (!req.body[key]) {
        res.json({code: code.paraErr, msg: errTips[key]})
        return
      }
    }
    // 验证图形验证码是否正确
    const captchaCache = await redis.get(captchaId)
    if (!captchaCache) {
      res.json({code: code.cacheErr, msg: '图形验证码已过期'})
      return
    }
    if (captchaText.toLowerCase() !== captchaCache.toLowerCase()) {
      res.json({code: code.paraErr, msg: '图形验证码错误'})
      // 删除缓存的图形验证码
      await redis.del(captchaId)
      return
    }
    // 删除缓存的图形验证码
    await redis.del(captchaId)
    const [errFind, results] = await db.query(User.findAllByEmail, [email])
    if (errFind) {
      res.json({code: code.dbErr, msg: '登录失败'})
      return
    }
    if (results.length === 0) {
      res.json({code: code.paraErr, msg: '没有此账户'})
      return
    }
    if (encryptPassword(password) !== results[0].password) {
      res.json({code: code.paraErr, msg: '密码错误'})
      return
    }
    delete results[0].password
    res.json({
      code: code.ok,
      data: {
        token: token.make({
          id: results[0].id
        }),
        user: {...results[0]}
      },
      msg: '登陆成功'
    })
  })()
})

router.post('/update', (req, res, next) => {
  (async () => {
    const { nickname, realname, phone, identity, avatar, address, school, gender } = req.body
    console.log(req.body)
    const errTips = {
      nickname: '请输入昵称',
      realname: '请输入姓名',
      phone: '请输入手机号码',
      identity: '请选择身份',
    }
    for (const key in errTips) {
      if (!req.body[key]) {
        return res.json({code: code.paraErr, msg: errTips[key]})
      }     
    }
    const [errUpdate, resUpdate] = await db.query(User.updateById, [nickname, realname, phone, identity, 
      avatar, address, school, gender, req.auth.id])
    if (errUpdate) {
      return res.json({
        code: code.dbErr,
        msg: '更新失败'
      })
    }
    if (resUpdate.affectedRows === 0) {
      return res.json({
        code: code.dbErr,
        msg: '更新失败'
      })
    }
    return res.json({
      code: code.ok,
      msg: '更新成功',
      data: req.body
    })
  })()
})

router.post('/reset', (req, res, next) => {
  (async () => {
    try {
      const { email, authcode, password } = req.body
      const errTips = {
        email: '请输入邮箱',
        authcode: '请输入验证码',
        password: '请输入新密码'
      }
      for (const key in errTips) {
        if (!req.body[key]) {
          res.json({code: code.paraErr, msg: errTips[key]})
          return
        }
      }
      // 查看缓存中是否已经缓存该数据
      const key = email + 'reset'
      const emailCache = await redis.hGetAll(key)
      if (Object.keys(emailCache).length === 0) {
        res.json({code: code.paraErr, msg: '请获取邮箱验证码'})
        return
      } else {
        if (emailCache.authcode !== authcode) {
          res.json({code: code.paraErr, msg: '邮箱验证码不正确'})
          return
        }
      }
      const [errFind, ids] = await db.query(User.findIdByEmail, [email])
      if (errFind) {
        res.json({code: code.dbErr, msg: '重置失败'})
        return
      }
      if (ids.length === 0) {
        res.json({code: code.paraErr, msg: '该用户未注册'})
        return
      }
      const [errSet, info] = await db.query(User.setPasswdByEmail, [encryptPassword(password), email])
      if (errSet) {
        res.json({code: code.dbErr, msg: '重置失败'})
        return
      }
      if (info.affectedRows === 0) {
        res.json({code: code.dbErr, msg: '重置失败'})
        return
      }
      res.json({code: code.ok, msg: '重置成功'})
    } catch(e) {
      res.json({code: code.insErr, msg: "重置失败"})
    }
  })()
})

router.post('/info', (req, res, next) => {
  (async () => {
    const userId = req.auth.id
    const [errFind, results] = await db.query(User.findAllById, [userId])
    if (errFind) {
      res.json({code: code.dbErr, msg: '获取用户信息失败'})
      return
    }
    if (results.length === 0) {
      res.json({code: code.err, msg: '获取用户信息失败'})
      return      
    }
    delete results[0].password
    res.json({
      code: code.ok,
      data: {...results[0]},
      msg: '获取成功'
    })
  })()
})

module.exports = router
